#include "sha256.h"

static sha256_uint32_t ShiftRightRotate(sha256_uint32_t v, int count)
{
	return (v >> count) | (v << (32 - count));
}


static void SHA256Cycle(sha256_uint32_t data[8], sha256_uint32_t seed, int round)
{
	static const sha256_uint32_t k[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
		0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
		0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
		0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
		0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
		0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
		0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
		0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };

	sha256_uint32_t ch = (data[4] & data[5]) ^ ((~data[4]) & data[6]);
	sha256_uint32_t s1 = ShiftRightRotate(data[4], 6) ^ ShiftRightRotate(data[4], 11) ^ ShiftRightRotate(data[4], 25);
	sha256_uint32_t combine1 = k[round] + seed + ch + data[7] + s1;
	sha256_uint32_t ma = (data[0] & data[1]) ^ (data[0] & data[2]) ^ (data[1] & data[2]);
	sha256_uint32_t s0 = ShiftRightRotate(data[0], 2) ^ ShiftRightRotate(data[0], 13) ^ ShiftRightRotate(data[0], 22);
	data[7] = data[6];
	data[6] = data[5];
	data[5] = data[4];
	data[4] = data[3] + combine1;
	data[3] = data[2];
	data[2] = data[1];
	data[1] = data[0];
	data[0] = combine1 + ma + s0;
}

void sha256(sha256_uint32_t data[8], const void *ptr, size_t n)
{
	const unsigned char *cptr = (const unsigned char *)ptr;
	int i;

	data[0] = 0x6a09e667;
	data[1] = 0xbb67ae85;
	data[2] = 0x3c6ef372;
	data[3] = 0xa54ff53a;
	data[4] = 0x510e527f;
	data[5] = 0x9b05688c;
	data[6] = 0x1f83d9ab;
	data[7] = 0x5be0cd19;

	while(n > 0)
	{
		sha256_uint32_t seeds[64];

		if(n >= 64)
		{
			for(i=0;i<64;i+=4)
			{
				seeds[i/4] = cptr[0] | (cptr[1] << 8) | (cptr[2] << 16) | (cptr[3] << 24);
				cptr += 4;
			}
			n -= 64;
		}
		else
		{
			for(i=0;i<64;i+=4)
				seeds[i/4] = cptr[i%n] | (cptr[(i+1)%n] << 8) | (cptr[(i+2)%n] << 16) | (cptr[(i+3)%n] << 24);
			n = 0;
		}

		for(i=16;i<64;i++)
		{
			sha256_uint32_t s0 = (ShiftRightRotate(seeds[i-15], 7) ^ ShiftRightRotate(seeds[i-15], 18) ^ ShiftRightRotate(seeds[i-15], 3));
			sha256_uint32_t s1 = (ShiftRightRotate(seeds[i-2], 17) ^ ShiftRightRotate(seeds[i-2], 19) ^ ShiftRightRotate(seeds[i-2], 10));
			seeds[i] = seeds[i-16] + seeds[i-7] + s0 + s1;
		}

		for(i=0;i<64;i++)
			SHA256Cycle(data, seeds[i], i);
	}
}
